using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using Castle.Core.Interceptor;

namespace ebcbinder
{
    internal class BindingInterceptor : IInterceptor
    {
        private Stack<long> openedGroups;

        public BindingInterceptor(Stack<long> openedGroups)
        {
            this.openedGroups = openedGroups;
        }


        public void Intercept(IInvocation invocation) {
            if (invocation.Method.Name.StartsWith("add_")) 
            {
                var inPin = (Delegate)invocation.Arguments[0];
                Type targetType = DetermineTargetType(inPin.Target);

                var wireDescription = string.Format("{6};{0};{1};{2};{3};{4};{5})", 
                                            invocation.InvocationTarget.GetHashCode(), 
                                            invocation.InvocationTarget.GetType().Name,
                                            invocation.Method.Name.Substring(4),

                                            inPin.Target == null ? 0 : inPin.Target.GetHashCode(),
                                            targetType.Name,
                                            inPin.Method.Name,
                                    
                                            this.openedGroups.Peek());

                Trace.TraceInformation("EbcBinder.BindingInterceptor: {0}\n", wireDescription);
                File.AppendAllLines("ebcbinder.log.csv", new[]{wireDescription});
            }

            invocation.Proceed();
        }


        private Type DetermineTargetType(object target)
        {
            if (target == null) return typeof (Action<>);

            if (target.GetType().Namespace.StartsWith("Castle.Proxies"))
            {
                FieldInfo targetField = target.GetType().GetField("__target",
                                                                  BindingFlags.NonPublic | BindingFlags.Public |
                                                                  BindingFlags.Instance | BindingFlags.FlattenHierarchy);
                return targetField.FieldType;
            }
            else
                return target.GetType();
        }
    }
}